package com.tlgen.orm.components.dataSource;

import lombok.Data;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class DataSourceContextHolder {
    // 使用线程安全的栈结构管理数据源切换（最大支持32层嵌套）
    private static final ThreadLocal<Deque<String>> CONTEXT_HOLDER =
            ThreadLocal.withInitial(ArrayDeque::new);

    // 数据源有效状态管理
    private static final ConcurrentHashMap<String, DataSourceInfo> ACTIVE_DATA_SOURCES =
            new ConcurrentHashMap<>();

    // 最大嵌套深度限制（防止无限递归）
    private static final int MAX_DEPTH = 32;

    // 性能计数器
    private static final AtomicInteger switchCount = new AtomicInteger(0);
    private static final AtomicInteger errorCount = new AtomicInteger(0);

    // 私有构造函数防止实例化
    private DataSourceContextHolder() {
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
    }

    /**
     * 设置当前数据源
     */
    public static void pushDataSource(String dataSourceName) {
        Objects.requireNonNull(dataSourceName, "DataSource name cannot be null");

        Deque<String> stack = CONTEXT_HOLDER.get();
        if (stack.size() >= MAX_DEPTH) {
            throw new IllegalStateException("Data source stack overflow (max depth " + MAX_DEPTH + ")");
        }
        stack.push(dataSourceName);
        switchCount.incrementAndGet();

        // 确保数据源已激活
        if (!ACTIVE_DATA_SOURCES.containsKey(dataSourceName)) {
            errorCount.incrementAndGet();
            throw new IllegalStateException("DataSource not configured: " + dataSourceName);
        }
    }

    /**
     * 获取当前数据源
     */
    public static String getCurrentDataSource() {
        Deque<String> stack = CONTEXT_HOLDER.get();
        return stack.isEmpty() ? null : stack.peek();
    }

    /**
     * 恢复前一个数据源
     */
    public static String popDataSource() {
        Deque<String> stack = CONTEXT_HOLDER.get();
        if (stack.isEmpty()) {
            errorCount.incrementAndGet();
            throw new IllegalStateException("No data source to pop from the context");
        }

        String popped = stack.pop();
        // 清理空的线程上下文
        if (stack.isEmpty()) {
            CONTEXT_HOLDER.remove();
        }
        return popped;
    }

    /**
     * 清除所有数据源上下文
     */
    public static void clear() {
        CONTEXT_HOLDER.remove();
    }

    /**
     * 检查是否设置了数据源
     */
    public static boolean hasDataSource() {
        Deque<String> stack = CONTEXT_HOLDER.get();
        return !stack.isEmpty();
    }

    /**
     * 添加有效数据源（在数据源初始化时调用）
     */
    public static void registerDataSource(String name, DataSourceInfo info) {
        ACTIVE_DATA_SOURCES.put(name, info);
    }

    /**
     * 移除/禁用数据源（在数据源关闭时调用）
     */
    public static void deregisterDataSource(String name) {
        ACTIVE_DATA_SOURCES.remove(name);
    }

    /**
     * 检查数据源是否有效
     */
    public static boolean isDataSourceActive(String name) {
        return ACTIVE_DATA_SOURCES.containsKey(name);
    }

    /**
     * 获取数据源信息
     */
    public static DataSourceInfo getDataSourceInfo(String name) {
        return ACTIVE_DATA_SOURCES.get(name);
    }

    // 获取所有已注册的数据源信息
    public static Collection<DataSourceInfo> getAllDataSourceInfos() {
        return ACTIVE_DATA_SOURCES.values();
    }

    /**
     * 在指定数据源上下文中执行操作
     */
    public static <T> T executeInContext(String dataSourceName, DataSourceAction<T> action) {
        String previous = getCurrentDataSource();
        try {
            pushDataSource(dataSourceName);
            return action.execute();
        } catch (Exception e) {
            errorCount.incrementAndGet();
            throw e;
        } finally {
            if (previous != null) {
                pushDataSource(previous);
            } else {
                popDataSource();
            }
        }
    }

    /**
     * 获取性能统计
     */
    public static DataSourceStats getStats() {
        return new DataSourceStats(
                switchCount.get(),
                errorCount.get(),
                ACTIVE_DATA_SOURCES.size()
        );
    }

    // ================ 内部类 ================

    @Data
    public static class DataSourceInfo {
        private final String name;
        private final String type;
        private final String driverClassName;
        private final String url;
        private final boolean readOnly;

        public DataSourceInfo(String name, String type, String driverClassName, String url, boolean readOnly) {
            this.name = name;
            this.type = type;
            this.driverClassName = driverClassName;
            this.url = url;
            this.readOnly = readOnly;
        }

    }

    public static class DataSourceStats {
        private final int switchCount;
        private final int errorCount;
        private final int activeDataSourceCount;

        public DataSourceStats(int switchCount, int errorCount, int activeDataSourceCount) {
            this.switchCount = switchCount;
            this.errorCount = errorCount;
            this.activeDataSourceCount = activeDataSourceCount;
        }

        // Getters
        public int getSwitchCount() { return switchCount; }
        public int getErrorCount() { return errorCount; }
        public int getActiveDataSourceCount() { return activeDataSourceCount; }
    }

    @FunctionalInterface
    public interface DataSourceAction<T> {
        T execute();
    }

}